package com.weixin.util;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
//import org.apache.log4j.Logger;

import java.util.Set;

import org.apache.commons.codec.digest.DigestUtils;

import com.alibaba.fastjson.JSONObject;
import com.dto.Signature;
import com.util.SHA1Util;
import com.weixin.config.Config;
import com.weixin.exception.WeixinException;
import com.weixin.vo.Article;
import com.weixin.vo.QunArticle;

/**
 * 微信工具类 WeixinUtil.java
 * 
 * 
 *  已经废弃 
 *  
 *  
 * @see com.weixin.service.WeiXinServiceImpl
 * @author microxdd
 * @time 创建时间：2014 2014年9月15日 下午2:50:05
 * @version
 * @user micrxdd
 */
@Deprecated
public class WeixinUtil {
    private final static String TOKEN = "token";

    // private static Logger log = Logger.getLogger(WeixinUtil.class);

    /**
     * 检验微信签名，验证消息的真实性
     * 
     * @param signature
     * @return JSONObject 消息的真实性
     */
    public static boolean ChackSignature(Signature signature) {
	if (signature != null && signature.getSignature() != null) {
	    List<String> params = new ArrayList<String>();
	    params.add(TOKEN);
	    params.add(signature.getTimestamp());
	    params.add(signature.getNonce());
	    Collections.sort(params, new Comparator<String>() {
		public int compare(String o1, String o2) {
		    return o1.compareTo(o2);
		}
	    });
	    // 2. 将三个参数字符串拼接成一个字符串进行sha1加密
	    String temp = SHA1Util.encode(params.get(0) + params.get(1)
		    + params.get(2));
	    System.out.println(temp);
	    if (temp.equals(signature.getSignature())) {
		return true;
	    }
	}
	return false;

    }

    // 获取tokenURL
    public static final String URL_ACCESSTOKEN = "https://api.weixin.qq.com/cgi-bin/token?access_token=";

    // 创建菜单URL
    public static final String URL_MENU_CREATE = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=";

    // 获取菜单URL
    public static final String URL_MENU_GET = "https://api.weixin.qq.com/cgi-bin/menu/get?access_token=";

    // 删除菜单URL
    public static final String URL_MENU_DELETE = "https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=";

    // 获取access_token的时间
    private static long getTime;

    // 当前获取的access_token(不用每次获取)
    private static String access_token;

    /**
     * 获取access_token
     * 
     * @return JSONObject access_token
     * @throws WeixinException
     */
    private static String getAccessToken() throws WeixinException {
	if (null != access_token) {// 已经获取了access_token
	    long currentTime = System.currentTimeMillis();
	    if ((currentTime - getTime) < 7200000) {// 过期了 |
						    // access_token有效期为7200秒
		return access_token;
	    }
	}

	// 从服务端从新获取access_token
	String url = URL_ACCESSTOKEN + "?" + "grant_type=" + Config.get("grant_type")
		+ "&appid=" + Config.get("APPID") + "&secret=" + Config.get("SECRET");

	String result = HttpUtil.Httpsget(url);
	getTime = System.currentTimeMillis();
	JSONObject obj = JSONObject.parseObject(result);
	String access_token = obj.getString("access_token");
	if (null == access_token) {// 错误
	    throw new WeixinException(result);
	}
	return access_token;
    }

    /**
     * 创建菜单
     * 
     * @param json
     * @throws WeixinException
     */
    public static void createMenu(String json) throws WeixinException {
	String url = URL_MENU_CREATE + getAccessToken();
	String result = HttpUtil.Httpspost(url, json);
	JSONObject obj = JSONObject.parseObject(result);
	int errcode = obj.getIntValue("errcode");
	if (errcode > 0) {
	    throw new WeixinException(result);
	}
    }

    /**
     * 查询菜单
     * 
     * @return JSONObject String json
     * @throws WeixinException
     */
    public static JSONObject findMenu() throws WeixinException {
	String result = HttpUtil.Httpsget(URL_MENU_GET + getAccessToken());
	return isSuccess(result);
    }

    /**
     * 删除菜单
     * 
     * @throws WeixinException
     */
    public static void deleteMenu() throws WeixinException {
	String url = URL_MENU_DELETE + getAccessToken();
	String result = HttpUtil.Httpsget(url);
	JSONObject obj = JSONObject.parseObject(result);
	int errcode = obj.getIntValue("errcode");
	if (errcode > 0) {
	    throw new WeixinException(result);
	}
    }

    // 创建用户组
    private static final String GROUP_CREATE_URI = "https://api.weixin.qq.com/cgi-bin/groups/create?access_token=";
    // 获取用户组
    private static final String GROUP_GET_URI = "https://api.weixin.qq.com/cgi-bin/groups/get?access_token=";
    // 根据id获取
    private static final String GROUP_GETID_URI = "https://api.weixin.qq.com/cgi-bin/groups/getid?access_token=";
    // 更新用户组
    private static final String GROUP_UPDATE_URI = "https://api.weixin.qq.com/cgi-bin/groups/update?access_token=";
    private static final String GROUP_MEMBERS_UPDATE_URI = "https://api.weixin.qq.com/cgi-bin/groups/members/update?access_token=";

    /**
     * 创建用户分组
     * 
     * @param groupname
     *            组名称
     * @return JSONObject JSONObject
     * @throws WeixinException
     */
    public static JSONObject createGroup(String groupname)
	    throws WeixinException {
	Map<String, Object> group = new HashMap<String, Object>();
	Map<String, Object> nameObj = new HashMap<String, Object>();
	nameObj.put("name", groupname);
	group.put("group", nameObj);
	String data = JSONObject.toJSONString(group);
	String result = HttpUtil.Httpspost(GROUP_CREATE_URI + getAccessToken(),
		data);
	JSONObject object = JSONObject.parseObject(result);
	if (object.getIntValue("errcode") != 0) {
	    throw new WeixinException(result);
	}
	return object;
    }

    /**
     * 获取所有的分组
     * 
     * @return JSONObject JSONObject
     * @throws WeixinException
     */
    public static JSONObject findAllGroups() throws WeixinException {
	String result = HttpUtil.Httpsget(GROUP_GET_URI + getAccessToken());
	return isSuccess(result);
    }

    /**
     * 根据openid查找用户
     * 
     * @param accessToken
     * @param openid
     * @return JSONObject
     * @throws WeixinException
     */
    public JSONObject findUserGroup(String openid) throws WeixinException {
	String result = HttpUtil.Httpsget(GROUP_GETID_URI + getAccessToken()
		+ "{\"openid\":\"" + openid + "\"}");
	return isSuccess(result);
    }

    /**
     * 修改分组名
     * 
     * @param accessToken
     * @param id
     *            分组id，由微信分配
     * @param name
     *            分组名字（30个字符以内）
     * @return JSONObject
     * @throws WeixinException
     */
    public JSONObject updateName(Integer id, String name)
	    throws WeixinException {
	Map<String, Object> group = new HashMap<String, Object>();
	Map<String, Object> nameObj = new HashMap<String, Object>();
	nameObj.put("name", name);
	nameObj.put("id", id);
	group.put("group", nameObj);
	String post = JSONObject.toJSONString(group);
	String result = HttpUtil.Httpspost(GROUP_UPDATE_URI + getAccessToken(),
		post);
	return isSuccess(result);

    }

    /**
     * 移动用户分组
     * 
     * @param accessToken
     * @param openid
     *            用户唯一标识符
     * @param to_groupid
     *            分组id
     * @return JSONObject
     * @throws WeixinException
     */
    public JSONObject membersMove(String openid, String to_groupid)
	    throws WeixinException {
	String result = HttpUtil.Httpspost(GROUP_MEMBERS_UPDATE_URI
		+ getAccessToken(), "{\"openid\":\"" + openid
		+ "\",\"to_groupid\":" + to_groupid + "}");
	return isSuccess(result);
    }
    /**
     * 判断数据是否提交成功
     * @param result
     * @return JSONObject
     * @throws WeixinException
     */
    public static JSONObject isSuccess(String result) throws WeixinException {
	JSONObject object = JSONObject.parseObject(result);
	if (object.getIntValue("errcode") != 0) {
	    throw new WeixinException(result);
	}
	return object;
    }

    private static final String MESSAGE_URL = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=";
    private static final String UPLOADNEWS_URL = "https://api.weixin.qq.com/cgi-bin/media/uploadnews?access_token=";
    private static final String MASS_SENDALL_URL = "https://api.weixin.qq.com/cgi-bin/message/mass/sendall?access_token=";
    private static final String MASS_SEND_URL = "https://api.weixin.qq.com/cgi-bin/message/mass/send?access_token=";
    private static final String MASS_DELETE_URL = "https://api.weixin.qq.com//cgi-bin/message/mass/delete?access_token=";

    /**
     * 发送客服消息
     * @param message
     * @return JSONObject
     * @throws Exception
     */
    private String sendMsg(Map<String, Object> message) throws Exception {
	String result = HttpUtil.Httpspost(MESSAGE_URL + getAccessToken(),
		JSONObject.toJSONString(message));
	return result;
    }

    /**
     * 发送文本客服消息
     * @param openId
     * @param text
     * @return JSONObject
     * @throws Exception
     */
    public String sendText(String openId, String text) throws Exception {
	Map<String, Object> json = new HashMap<String, Object>();
	Map<String, Object> textObj = new HashMap<String, Object>();
	textObj.put("content", text);
	json.put("touser", openId);
	json.put("msgtype", "text");
	json.put("text", textObj);
	String result = sendMsg(json);
	return result;
    }
    /**
     * 发送图片消息
     * @param openId
     * @param media_id
     * @return JSONObject
     * @throws Exception
     */
    public String SendImage(String openId, String media_id) throws Exception {
	Map<String, Object> json = new HashMap<String, Object>();
	Map<String, Object> textObj = new HashMap<String, Object>();
	textObj.put("media_id", media_id);
	json.put("touser", openId);
	json.put("msgtype", "image");
	json.put("image", textObj);
	String result = sendMsg(json);
	return result;
    }

    
    /**
     * 发送语言回复
     * @param openId
     * @param media_id
     * @return JSONObject
     * @throws Exception
     */
    public String SendVoice(String openId, String media_id) throws Exception {
	Map<String, Object> json = new HashMap<String, Object>();
	Map<String, Object> textObj = new HashMap<String, Object>();
	textObj.put("media_id", media_id);
	json.put("touser", openId);
	json.put("msgtype", "voice");
	json.put("voice", textObj);
	String result = sendMsg(json);
	return result;
    }

    /**
     * 发送视频回复
     * @param openId
     * @param media_id
     * @param title
     * @param description
     * @return JSONObject
     * @throws Exception
     */
    public String SendVideo(String openId, String media_id, String title,
	    String description) throws Exception {
	Map<String, Object> json = new HashMap<String, Object>();
	Map<String, Object> textObj = new HashMap<String, Object>();
	textObj.put("media_id", media_id);
	textObj.put("title", title);
	textObj.put("description", description);

	json.put("touser", openId);
	json.put("msgtype", "video");
	json.put("video", textObj);
	String result = sendMsg(json);
	return result;
    }

    /**
     * 发送音乐回复
     * @param openId
     * @param musicurl
     * @param hqmusicurl
     * @param thumb_media_id
     * @param title
     * @param description
     * @return JSONObject
     * @throws Exception
     */
    public String SendMusic(String openId, String musicurl, String hqmusicurl,
	    String thumb_media_id, String title, String description)
	    throws Exception {
	Map<String, Object> json = new HashMap<String, Object>();
	Map<String, Object> textObj = new HashMap<String, Object>();
	textObj.put("musicurl", musicurl);
	textObj.put("hqmusicurl", hqmusicurl);
	textObj.put("thumb_media_id", thumb_media_id);
	textObj.put("title", title);
	textObj.put("description", description);

	json.put("touser", openId);
	json.put("msgtype", "music");
	json.put("music", textObj);
	String result = sendMsg(json);
	return result;
    }

    /**
     * 发送图文回复
     * @param openId
     * @param articles
     * @return JSONObject
     * @throws Exception
     */
    public String SendNews(String openId, List<Article> articles)
	    throws Exception {
	Map<String, Object> json = new HashMap<String, Object>();
	json.put("touser", openId);
	json.put("msgtype", "news");
	json.put("news", articles);
	String result = sendMsg(json);
	return result;
    }

    /**
     * 上传图文消息素材
     * @param articles
     * @return JSONObject
     * @throws WeixinException
     */
    public JSONObject uploadnews(List<QunArticle> articles)
	    throws WeixinException {
	Map<String, Object> json = new HashMap<String, Object>();
	json.put("articles", articles);
	String result = HttpUtil.Httpspost(UPLOADNEWS_URL + getAccessToken(),
		JSONObject.toJSONString(json));
	return isSuccess(result);
    }

    /**
     * 根据分组进行群发
     * @param groupId
     * @param mpNewsMediaId
     * @return JSONObject
     * @throws WeixinException
     */
    public JSONObject massSendall(String groupId, String mpNewsMediaId)
	    throws WeixinException {
	Map<String, Object> json = new HashMap<String, Object>();
	Map<String, Object> filter = new HashMap<String, Object>();
	Map<String, Object> mpnews = new HashMap<String, Object>();
	filter.put("group_id", groupId);
	mpnews.put("media_id", mpNewsMediaId);

	json.put("mpnews", mpnews);
	json.put("filter", filter);
	json.put("msgtype", "mpnews");
	String result = HttpUtil.Httpspost(MASS_SENDALL_URL + getAccessToken(),
		JSONObject.toJSONString(json));
	return isSuccess(result);
    }

    /**
     * 根据OpenID列表群发
     * @param openids
     * @param mpNewsMediaId
     * @return JSONObject
     * @throws WeixinException
     */
    public static JSONObject massSend(String[] openids, String mpNewsMediaId)
	    throws WeixinException {
	Map<String, Object> json = new HashMap<String, Object>();
	Map<String, Object> mpnews = new HashMap<String, Object>();
	mpnews.put("media_id", mpNewsMediaId);
	json.put("touser", openids);
	json.put("mpnews", mpnews);
	json.put("msgtype", "mpnews");
	String result = HttpUtil.Httpspost(MASS_SEND_URL + getAccessToken(),
		JSONObject.toJSONString(json));
	return isSuccess(result);
    }

    /**
     * 删除群发
     * @param msgid
     * @return JSONObject
     * @throws WeixinException
     */
    public static JSONObject massSend(String msgid) throws WeixinException {
	Map<String, Object> json = new HashMap<String, Object>();
	json.put("msgid", msgid);
	String result = HttpUtil.Httpspost(MASS_DELETE_URL + getAccessToken(),
		JSONObject.toJSONString(json));
	return isSuccess(result);
    }

    private static final String USER_INFO_URI = "https://api.weixin.qq.com/cgi-bin/user/info?lang=zh_CN&access_token=";
    private static final String USER_GET_URI = "https://api.weixin.qq.com/cgi-bin/user/get?access_token=";

    /**
     * 拉取用户信息
     * @param openid
     * @return JSONObject
     * @throws WeixinException
     */
    public JSONObject getUserInfo(String openid) throws WeixinException {
	String result = HttpUtil.Httpsget(USER_INFO_URI + getAccessToken()
		+ "&openid=" + openid);
	return isSuccess(result);
    }

    /**
     * 获取帐号的关注者列表
     * @param next_openid
     * @return JSONObject
     * @throws WeixinException
     */
    public JSONObject getFollwersList(String next_openid)
	    throws WeixinException {
	String result = HttpUtil.Httpsget(USER_GET_URI + getAccessToken()
		+ "&next_openid=" + next_openid);
	return isSuccess(result);
    }

    private static final String QRCOD_CREATE = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=";

    private static final String QRCOD_SHOW = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=";

    /**
     * 创建临时二维码
     * 
     * @param accessToken
     * @param expireSeconds
     *            最大不超过1800
     * @param sceneId
     *            场景值ID，临时二维码时为32位非0整型，永久二维码时最大值为100000（目前参数只支持1--100000）
     * @return JSONObject JSONObject
     * @throws WeixinException
     */
    public JSONObject createScene(int expireSeconds,
	    int sceneId) throws WeixinException {
	Map<String, Object> params = new HashMap<String, Object>();
	Map<String, Object> actionInfo = new HashMap<String, Object>();
	Map<String, Object> scene = new HashMap<String, Object>();
	params.put("expire_seconds", expireSeconds);
	params.put("action_name", "QR_SCENE");
	scene.put("scene_id", sceneId);
	actionInfo.put("scene", scene);
	params.put("action_info", actionInfo);
	String post = JSONObject.toJSONString(params);
	String result = HttpUtil.Httpspost(QRCOD_CREATE+getAccessToken(), post);
	return isSuccess(result);
    }

    /**
     * 创建永久二维码
     * @param sceneId
     * @return
     * @throws WeixinException
     */
    public JSONObject createLimitScene(int sceneId)
	    throws WeixinException {
	Map<String, Object> params = new HashMap<String, Object>();
	Map<String, Object> actionInfo = new HashMap<String, Object>();
	Map<String, Object> scene = new HashMap<String, Object>();
	params.put("action_name", "QR_LIMIT_SCENE");
	scene.put("scene_id", sceneId);
	actionInfo.put("scene", scene);
	params.put("action_info", actionInfo);
	String post = JSONObject.toJSONString(params);
	String result = HttpUtil.Httpspost(QRCOD_CREATE+getAccessToken(), post);
	return isSuccess(result);
    }

    /**
     * 获取查看二维码链接
     * 
     * @param ticket
     * @return StringUrl
     */
    public static String showqrcodeUrl(String ticket) {
	return QRCOD_SHOW.concat(ticket);
    }
 // 发货通知接口
    private static final String DELIVERNOTIFY_URL = "https://api.weixin.qq.com/pay/delivernotify?access_token=";

    /**
     * 参与 paySign 签名的字段包括：appid、timestamp、noncestr、package 以及 appkey。
     * 这里 signType 并不参与签名微信的Package参数
     * @param params
     * @return
     * @throws UnsupportedEncodingException 
     */
    public static String getPackage(Map<String, String> params) throws UnsupportedEncodingException {
        String partnerKey = Config.get("partnerKey");
        String partnerId = Config.get("partnerId");
        String notifyUrl = Config.get("notify_url");
        // 公共参数
        params.put("bank_type", "WX");
        params.put("attach", "yongle");
        params.put("partner", partnerId);
        params.put("notify_url", notifyUrl);
        params.put("input_charset", "UTF-8");
        return packageSign(params, partnerKey);
    }

    /**
     * 构造签名
     * @param params
     * @param encode
     * @return
     * @throws UnsupportedEncodingException 
     */
    public static String createSign(Map<String, String> params, boolean encode) throws UnsupportedEncodingException{
        Set<String> keysSet = params.keySet();
        Object[] keys = keysSet.toArray();
        Arrays.sort(keys);
        StringBuffer temp = new StringBuffer();
        boolean first = true;
        for (Object key : keys) {
            if (first) {
                first = false;
            } else {
                temp.append("&");
            }
            temp.append(key).append("=");
            Object value = params.get(key);
            String valueString = "";
            if (null != value) {
                valueString = value.toString();
            }
            if (encode) {
                temp.append(URLEncoder.encode(valueString, "UTF-8"));
            } else {
                temp.append(valueString);
            }
        }
        return temp.toString();
    }

    /**
     * 构造package, 这是我见到的最草蛋的加密，尼玛文档还有错
     * @param params
     * @param paternerKey
     * @return
     * @throws UnsupportedEncodingException 
     */
    private static String packageSign(Map<String, String> params, String paternerKey) throws UnsupportedEncodingException {
        String string1 = createSign(params, false);
        String stringSignTemp = string1 + "&key=" + paternerKey;
        String signValue = DigestUtils.md5Hex(stringSignTemp).toUpperCase();
        String string2 = createSign(params, true);
        return string2 + "&sign=" + signValue;
    }

    /**
     * 支付签名
     * @param timestamp
     * @param noncestr
     * @param packages
     * @return
     * @throws UnsupportedEncodingException 
     */
    public static String paySign(String timestamp, String noncestr,String packages) throws UnsupportedEncodingException {
        Map<String, String> paras = new HashMap<String, String>();
        paras.put("appid", Config.get("AppId"));
        paras.put("timestamp", timestamp);
        paras.put("noncestr", noncestr);
        paras.put("package", packages);
        paras.put("appkey", Config.get("paySignKey"));
        // appid、timestamp、noncestr、package 以及 appkey。
        String string1 = createSign(paras, false);
        String paySign = DigestUtils.sha1Hex(string1);
        return paySign;
    }
    
    /**
     * 支付回调校验签名
     * @param timestamp
     * @param noncestr
     * @param openid
     * @param issubscribe
     * @param appsignature
     * @return
     * @throws UnsupportedEncodingException 
     */
    public static boolean verifySign(long timestamp,
            String noncestr, String openid, int issubscribe, String appsignature) throws UnsupportedEncodingException {
        Map<String, String> paras = new HashMap<String, String>();
        paras.put("appid", Config.get("AppId"));
        paras.put("appkey", Config.get("paySignKey"));
        paras.put("timestamp", String.valueOf(timestamp));
        paras.put("noncestr", noncestr);
        paras.put("openid", openid);
        paras.put("issubscribe", String.valueOf(issubscribe));
        // appid、appkey、productid、timestamp、noncestr、openid、issubscribe
        String string1 = createSign(paras, false);
        String paySign = DigestUtils.sha1Hex(string1);
        return paySign.equalsIgnoreCase(appsignature);
    }
    
    /**
     * 发货通知签名
     * @param paras
     * @return
     * @throws UnsupportedEncodingException
     * 
     * @参数 appid、appkey、openid、transid、out_trade_no、deliver_timestamp、deliver_status、deliver_msg；
     */
    private static String deliverSign(Map<String, String> paras) throws UnsupportedEncodingException {
        paras.put("appkey", Config.get("paySignKey"));
        String string1 = createSign(paras, false);
        String paySign = DigestUtils.sha1Hex(string1);
        return paySign;
    }
    
    
    /**
     * 发货通知
     * @param access_token
     * @param openid
     * @param transid
     * @param out_trade_no
     * @return
     * @throws WeixinException 
     * @throws UnsupportedEncodingException 
     */

    public static boolean delivernotify(String openid, String transid, String out_trade_no) throws WeixinException, UnsupportedEncodingException {
        Map<String, String> paras = new HashMap<String, String>();
        paras.put("appid", Config.get("AppId"));
        paras.put("openid", openid);
        paras.put("transid", transid);
        paras.put("out_trade_no", out_trade_no);
        paras.put("deliver_timestamp", (System.currentTimeMillis() / 1000) + "");
        paras.put("deliver_status", "1");
        paras.put("deliver_msg", "ok");
        // 签名
        String app_signature = deliverSign(paras);
        paras.put("app_signature", app_signature);
        paras.put("sign_method", "sha1");
        String result = HttpUtil.Httpspost(DELIVERNOTIFY_URL+ getAccessToken(), JSONObject.toJSONString(paras));
        isSuccess(result);
        return false;
    }

}